Skip to content

Generate the endpoint reference from the OpenAPI spec - #12

Open
joshk wants to merge 3 commits into
mainfrom
openapi-generated-reference
Open

Generate the endpoint reference from the OpenAPI spec#12
joshk wants to merge 3 commits into
mainfrom
openapi-generated-reference

Conversation

@joshk

@joshk joshk commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

The API Reference tab now builds its endpoint reference from the specification the server generates and serves.

{
  "group": "Endpoints",
  "openapi": "https://manage.nervescloud.com/api/openapi"
}

What this fixes

Before After
Operations documented 34 77
Operations missing 50 0
Operations documented that do not exist 1 0

The one that did not exist:

docs said:  POST /api/orgs/{org}/products/{product}/devices        -> 404
actually:   POST /api/orgs/{org}/products/{product}/devices/{identifier}

The identifier goes in the path, not the body, so anyone following the old "Create a Device" example got a 404. Generating from the spec makes that class of error impossible rather than fixing this one instance.

Newly covered, having been absent entirely: the whole /api/devices/{identifier}/* short-URL family (reboot, reconnect, upgrade, move, logs, code, scripts, penalty), support scripts, Iroh endpoints, network identities, bulk device import, organization members, signing keys, CLI session auth and platform status.

Structure

The spec tags all 77 operations across 16 tags with none untagged, so the generated section groups by resource — Devices, Products, Firmwares, Deployment Groups and so on — rather than arriving as one flat list of 77.

Overview and Authentication stay hand-written. They cover base URLs, the response envelope, and the status code table, none of which the spec carries. Device WebSocket is untouched.

The four resource pages are deleted and redirect to /api/overview; only one link existed between them, and both ends are gone.

Worth knowing

The build now depends on manage.nervescloud.com being reachable. Mintlify fetches remote specs at build time. It is public today — 200, application/json, 134 KB, OpenAPI 3.0.0. If you would rather not couple builds to it, the alternative is committing a periodically-refreshed copy, at the cost of freshness.

The reference describes NervesCloud. A self-hosted deployment exposes the same API, but an older one may differ. Noted on the overview page, pointing readers at their own /api/openapi.

Please eyeball the preview

I validated docs.json against the Mintlify schema, confirmed all 32 remaining hand-written pages resolve, and checked every internal link and redirect. What I cannot verify without a build is how the generated section renders — grouping, ordering and playground behaviour. Worth a look at the preview before merging.

🤖 Generated with Claude Code

The hand-written resource pages covered 34 of the API's 77 operations,
and one of them documented a create-device call that does not exist:
the identifier goes in the path, not the body.

The API Reference tab now points at the specification the server
generates, so the endpoint reference is complete and cannot drift. The
spec tags every operation, so it groups by resource rather than
arriving as one flat list.

Overview and Authentication stay hand-written, since base URLs, response
envelopes and status codes are not in the spec. The four resource pages
are removed and redirect to the overview.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Sep 5, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
NervesHub 🔴 Failed Sep 5, 2026, 6:26 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

joshk and others added 2 commits September 5, 2026 18:32
Deployment: Mintlify could not fetch the spec from the remote URL, so
it built with no OpenAPI file at all. The spec is now checked in as
openapi.json and referenced by path, which is the mechanism Mintlify
uses by default and removes the build's dependency on the production
host being reachable.

Link-rot: the anchor #device-server-events did not exist. Mintlify keeps
the arrow when slugifying, so the real anchor is #device-→-server-events.
The link now points at #rebooting, which is the event the sentence is
actually about and has a clean slug.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The build reported "Failed to fetch OpenAPI file for anchor or tab" and
"Fetched 0 OpenApi file(s)" with the spec on a group, both when it was a
remote URL and after it was checked in, so the file was never the
problem. Group-level openapi appears not to be picked up by this
deployment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@joshk

joshk commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

CI diagnosis: the spec itself is invalid

The deployment failure is not a configuration problem in this repo. NervesHub publishes an OpenAPI document that fails OpenAPI 3.0 validation, so Mintlify rejects it and reports Fetched 0 OpenApi file(s).

Ruled out along the way, each with its own CI run:

Tried Result
Remote URL on a group Fetched 0 OpenApi file(s)
Spec checked in as openapi.json, referenced by path identical failure
openapi moved from the group to the tab identical failure

Same error in all three, which is what pointed at the document rather than the wiring. The URL is fine on its own: 200, no redirect, application/json, 134 KB.

Two defects, both in nerves_hub_web

1. Boolean required on schema properties — 15 of them, all in @filters_parameter in lib/nerves_hub_web/controllers/api/openapi/device_controller_specs.ex:

alarm: %OpenApiSpex.Schema{type: :string, required: false, example: "SomeAlarm"},

In OpenAPI 3.x, required on a Schema Object must be an array of property names on the parent object. A boolean there is a Swagger 2.0 form. Properties are optional by default, so these can simply be deleted. (required: false on the %OpenApiSpex.Parameter{} entries in the same file is correct and should stay.)

2. Duplicate operationIds — 8 of them. Every device action is published under both URL shapes and reuses one id:

NervesHubWeb.API.DevicesController.code
  POST /api/devices/{identifier}/code
  POST /api/orgs/{org_name}/products/{product_name}/devices/{identifier}/code

Also show, reboot, reconnect, upgrade, move, penalty, and ScriptController.send. OpenAPI requires operationId to be unique document-wide.

The codebase already has the fix pattern — device_log_controller_specs.ex disambiguates with the path structure:

operationId: "NervesHubWeb.API.DeviceLogController.index.#{path_structure}",

device_controller_specs.ex does not, at lines 482 and 496.

Applying both fixes locally makes the document pass OpenAPI 3.0 validation cleanly.

Impact beyond these docs

An invalid spec breaks any consumer, not just Mintlify — Postman, Insomnia, and client generators will reject or mis-handle it too. Worth fixing upstream regardless of what happens to this PR.

This PR is blocked

It cannot go green until manage.nervescloud.com serves a valid document. Holding rather than committing a hand-patched copy, since publishing a spec that differs from the server's would defeat the point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant